﻿/*
COPYRIGHT (C) 2008 EPISERVER AB

THIS FILE IS PART OF SCRUM DASHBOARD.

SCRUM DASHBOARD IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF 
THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

SCRUM DASHBOARD IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT
EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER
GENERAL PUBLIC LICENSE FOR MORE DETAILS.

YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH SCRUM DASHBOARD. 
IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/
using System.Web.Services;
using System.Web.Services.Protocols;
using ScrumDashboard.Library;
using ScrumDashboard.Library.Entities;
using ScrumDashboard.Library.Tfs;

namespace ScrumDashboard.Notification
{
    /// <summary>
    /// Web Service Endpoint for the <see cref="WorkItemChangedEvent"/>
    /// </summary>
    /// <remarks>
    /// To Register this Notification Endpoint you will need to use the <see cref="http://blogs.msdn.com/psheill/archive/2006/02/01/522386.aspx">BisSubscribe.exe</see> tool. 
    /// For more information about Team Foundation Server Notifications <see cref="http://blogs.msdn.com/buckh/archive/2006/04/10/event_filtering.aspx"/>
    /// </remarks>
    [WebService(Namespace = "http://schemas.conchango.com/TeamFoundation/2005/06/Services/Notification/Extensibility", Description = "")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class WorkItemChanged : EndpointBase
    {
        /// <summary>
        /// Endpoint required to accept incoming <see cref="WorkItemChangedEvent"/> notifications
        /// </summary>
        /// <param name="eventXml">Serialized version of the <see cref="WorkItemChangedEvent"/></param>
        /// <param name="tfsIdentityXml">Serialized version of <see cref="TFSIdentity"/></param>
        [WebMethod]
        [SoapDocumentMethod("http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", RequestNamespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
        public void Notify(string eventXml, string tfsIdentityXml)
        {
            WorkItemChangedEvent workItemChangedEvent = this.CreateInstance<WorkItemChangedEvent>(eventXml);
            TFSIdentity tfsIdentity = this.CreateInstance<TFSIdentity>(tfsIdentityXml);

            TfsCacheDependency.FireTfsChanged(workItemChangedEvent.PortfolioProject);

            if (!IsProductBacklogItem(workItemChangedEvent))
                return;

            if (HasInterestingStringFieldsChanged(workItemChangedEvent) || HasInterestingIntegerFieldsChanged(workItemChangedEvent))
            {
                int revision = 0;
                int id = 0;
                bool changedState = false;
                if (GetBaseData(workItemChangedEvent, ref revision, ref id, ref changedState))
                    DBHelper.AddWorkItemEvent(workItemChangedEvent.PortfolioProject, id, revision, workItemChangedEvent.ChangeType == ChangeTypes.New, changedState, "Product Backlog Item");
            }
        }

        private bool IsProductBacklogItem(WorkItemChangedEvent workItemChangedEvent)
        {
            foreach (StringField coreField in workItemChangedEvent.CoreFields.StringFields)
            {
                if(coreField.Name=="Work Item Type")
                    return coreField.OldValue=="Product Backlog Item";
            }

            return false;
        }

        private static bool GetBaseData(WorkItemChangedEvent workItemChangedEvent, ref int revision, ref int id, ref bool changedstate)
        {
            foreach (IntegerField coreField in workItemChangedEvent.CoreFields.IntegerFields)
            {
                if (coreField.ReferenceName == "System.Rev")
                {
                    revision = coreField.NewValue;
                }
                if (coreField.ReferenceName == "System.Id")
                {
                    id = coreField.NewValue;
                }

                if (coreField.ReferenceName == "System.State")
                {
                    changedstate = coreField.OldValue != coreField.NewValue;
                }
            }

            foreach (StringField coreField in workItemChangedEvent.CoreFields.StringFields)
            {
                if (coreField.ReferenceName == "System.State")
                {
                    changedstate = coreField.OldValue != coreField.NewValue;
                    break;
                }
            }

            return id>0;
        }

        private static bool HasInterestingIntegerFieldsChanged(WorkItemChangedEvent workItemChangedEvent)
        {
            foreach (IntegerField f in workItemChangedEvent.ChangedFields.IntegerFields)
            {
                if (f.Name == "System.IterationId" && f.NewValue != f.OldValue)
                    return true;
                if (f.Name == ConchangoFields.BusinessPriority && f.NewValue != f.OldValue)
                    return true;
            }
            return false;
        }

        private static bool HasInterestingStringFieldsChanged(WorkItemChangedEvent workItemChangedEvent)
        {
            foreach (StringField f in workItemChangedEvent.ChangedFields.StringFields)
            {
                if (f.Name == "State" && f.NewValue != f.OldValue)
                    return true;

                if (f.Name == "Description" && f.NewValue != f.OldValue)
                    return true;

                if (f.Name == "Title" && f.NewValue != f.OldValue)
                    return true;

                if (f.Name == ConchangoFields.Team && f.NewValue != f.OldValue)
                    return true;
            }
            return false;
        }
    }
}